package com.itheima.dubbo.mongodb.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.commons.model.mongo.Publish;
import com.itheima.commons.model.mongo.TimeLine;
import com.itheima.dubbo.interfaces.PublishApi;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class PublishApiImpl implements PublishApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public String publish(Publish publish) {
        // 直接往发布表中添加一条记录就可以了
        Publish pub = mongoTemplate.save(publish);
        return pub.getId().toHexString();
    }

    @Override
    public List<Publish> findFriendMovements(Integer page, Integer pagesize, Long userId) {
        // 查询自己的时间线表
        List<TimeLine> timeLines = mongoTemplate.find(new Query()
                        .with(Sort.by(Sort.Order.desc("date")))
                        .with(PageRequest.of(page - 1, pagesize))
                , TimeLine.class, "quanzi_time_line_" + userId);
        List<ObjectId> publishIds = CollUtil.getFieldValues(timeLines, "publishId", ObjectId.class);
        // 根据上面的圈子id去查询发布表
        List<Publish> publishList = mongoTemplate.find(Query.query(Criteria.where("id").in(publishIds)), Publish.class);
        return publishList;
    }

    @Override
    public List<Publish> findMovementsByPids(List<Long> pids) {
        // 从MongoDB去查询
        return mongoTemplate.find(Query.query(Criteria.where("pid").in(pids)), Publish.class);
    }

    @Override
    public List<Publish> randomMovements(Integer pagesize) {
        // 从MongoDB中随机抽样数据
        AggregationResults<Publish> aggregationResults = mongoTemplate.aggregate(Aggregation.newAggregation(Publish.class, Aggregation.sample(Convert.toLong(pagesize))),
                Publish.class);
        List<Publish> mappedResults = aggregationResults.getMappedResults();
        return mappedResults;
    }

    // 评论详情页上的圈子内容
    @Override
    public Publish queryPublishById(String id) {
        return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id)), Publish.class);
    }

    @Override
    public List<Publish> findAll() {
        List<Publish> list = mongoTemplate.findAll(Publish.class);
        return list;
    }

    @Override
    public Integer queryStatus(String id) {
        Publish publish = mongoTemplate.findOne(Query.query(Criteria.where("id").is(new ObjectId(id))), Publish.class);
        return publish.getStatus();
    }

    @Override
    public List<Publish> queryPublishByUid(List<Long> uids, Integer page, Integer pagesize,String sortProp, String sortOrder) {
        List<Publish> publishes ;
        if ("descending".equals(sortOrder)) {
           publishes = mongoTemplate.find(Query.query(Criteria.where("userId").in(uids))
                    .with(Sort.by(Sort.Order.desc("topState"),
                            Sort.Order.desc(sortProp),
                            Sort.Order.desc("opsCreatedTime")))
                    .with(PageRequest.of(page - 1, pagesize)), Publish.class);
        } else {
            publishes = mongoTemplate.find(Query.query(Criteria.where("userId").in(uids))
                    .with(Sort.by(Sort.Order.desc("topState"),
                            Sort.Order.asc(sortProp),
                            Sort.Order.desc("opsCreatedTime")))
                    .with(PageRequest.of(page - 1, pagesize)), Publish.class);
        }
        return publishes;
    }

    @Override
    public List<Publish> queryPublishByUid(List<Long> uids, Integer page, Integer pagesize, Long sd, Long ed) {
        List<Publish> publishes = mongoTemplate.find(Query.query(Criteria.where("userId").in(uids)
                .and("created").gte(sd).lte(ed))
                .with(Sort.by(Sort.Order.desc("topState")
                        , Sort.Order.by("opsCreatedTime"))
                )
                .with(PageRequest.of(page - 1, pagesize)), Publish.class);
        return publishes;
    }

    @Override
    public List<Publish> queryPublishByUid(List<Long> uids, Integer page, Integer pagesize, Long sd, Long ed, int status) {
        List<Publish> publishes = mongoTemplate.find(Query.query(Criteria.where("userId").in(uids)
                .and("status").is(status)
                .and("created").gte(sd).lte(ed))
                .with(Sort.by(Sort.Order.desc("topState")
                        , Sort.Order.by("opsCreatedTime"))
                )
                .with(PageRequest.of(page - 1, pagesize)), Publish.class);
        return publishes;
    }

    @Override
    public void setAuditing(ObjectId id, Long opsUserId, int status) {
        Update up = Update.update("opsUserId", opsUserId);
        up.set("status", status);
        up.set("opsDatetime", System.currentTimeMillis());
        mongoTemplate.upsert(Query.query(Criteria.where("id").is(id)), up, Publish.class);
    }

    @Override
    public void setTop(ObjectId id, int i) {
        mongoTemplate.upsert(Query.query(Criteria.where("id").is(id)),
                Update.update("topState", i).set("opsDatetime", System.currentTimeMillis()), Publish.class);
    }

    /**
     * 根据管理员ids，时间区间，获取信息//因为没有这个表字段，如果有文本传入，就说明是冻结的那一块，即有文本内容就返回空
     *
     * @param adminIds
     * @param endTime
     * @param startTime
     * @return
     */
    @Override
    public List<Publish> queryByAdminIdsAndTimeAndFreezeRemarks(List<Long> adminIds, Date endTime, Date startTime, String operationContent) {
        List<Publish> publishes = new ArrayList<>();
        if (StrUtil.isBlank(operationContent)) {
            publishes = mongoTemplate.find(Query.query(Criteria
                    .where("opsUserId").in(adminIds)
                    .and("date").gte(startTime.getTime()).lte(endTime.getTime())
            ), Publish.class);
        }
        return publishes;
    }

    @Override
    public Long countByStatus(int status) {
        long count = mongoTemplate.count(Query.query(Criteria.where("status").is(status)), Publish.class);
        return count;
    }

    @Override
    public Long countOneByStatus(String uid, int status) {
        long count = mongoTemplate.count(Query.query(Criteria.where("status").is(status)
                .and("userId").is(Convert.toLong(uid))), Publish.class);
        return count;
    }
}
